這題是常見的二元樹問題,給兩個不同遍歷順序 (中序遍歷和後序遍歷)構建對應的二元樹。
思路:
先理解中序和後序遍歷的特色:
中序遍歷是左子樹 -> 根節點 -> 右子樹,後面遍歷是左子樹 -> 右子樹 -> 根節點用後序遍歷的特性,可知後序遍歷的最後一個元素是根節點,中序遍歷可以幫助定位根節點在樹中的位置,並推導出左、右子樹的元素範圍。
用遞迴構建樹:
確定根節點後,可以把中序遍歷分成左右兩部分,左邊對應左子樹,右邊對應右子樹,然後,從後序遍歷中找到對應的左右子樹元素,用遞迴處理,每次遞迴就能從後序遍歷中確定當前子樹的根節點,再把問題繼續分解成更小的問題,要追蹤後序遍歷的根節點位置,再不斷更新中序遍歷的索引來區分左右子樹,每次處理後序遍歷中的最後一個元素作為根,再把它分割成左右兩部分後,重複這個步驟直到樹建完。
重點:
用字典加速查詢,在中序遍歷中找根節點的位置如果用線性查找會比較耗時間,所以可以先把中序遍歷的值和索引存到字典裡,這樣可以在 O(1) 時間內找到根的位置,提高演算法效率,減少不必要的計算,在遞迴過程中,只需要處理當前範圍的節點,這樣可以避免處理無關的數據。
程式碼:
#Definition for a binary tree node.
#class TreeNode(object):
#def init(self, val=0, left=None, right=None):
#self.val = val
#self.left = left
#self.right = right
class Solution(object):
def buildTree(self, inorder, postorder):
"""
:type inorder: List[int]
:type postorder: List[int]
:rtype: TreeNode
"""
if not inorder or not postorder:
return None
#後序遍歷的最後一個元素是根節點
root_val = postorder.pop()
root = TreeNode(root_val)
#根節點在中序遍歷中的索引
inorder_index = inorder.index(root_val)
#先構建右子樹,再構建左子樹
root.right = self.buildTree(inorder[inorder_index+1:], postorder)
root.left = self.buildTree(inorder[:inorder_index], postorder)
return root
解釋:
root_val = postorder.pop(),從後序遍歷取出最後一個元素當作根節點,inorder.index(root_val),在中序遍歷中找到根節點的位置,然後把中序遍歷劃分成左子樹和右子樹,遞迴建左右子樹,先建右子樹,因為後序遍歷是先存左子樹,再來才是右子樹,最後是根節點,所以先遞迴處理右子樹,然後處理左子樹,遞迴結束條件,當 inorder 或 postorder 是空,表示已經沒有節點要處理,返回 None。
心得:
這題讓我更理解麼遍歷構建二元樹,用遞迴的方式把大問題拆解解決,還有,通過合理用資料結構,像是字典來加速查找操作,學到如何提高演算法的效率,在解決這個問題時,我也複習了對二元樹不同遍歷方式的理解,尤其是從後序遍歷裡判斷根節點再用中序遍歷來分割左右子樹。